<?php

/**
 * Gives failsafe and asynchronous access to data from a REST server.  This is 
 * to avoid needing to hit a server before rendering a page containing data 
 * from a REST feed, eg. Flickr, Twitter, weather information.
 * Also solves issues where a server isn't found causes pages to time out or 
 * gives errors using the standard RestfulService class.
 * Doesn't try to parse the feed into a RestfulService_Response object like 
 * RestfulService, so you can consume JSON, XML, or any other type of data
 * safely.  You just get the bare string output.
 */

class RestfulSubscription extends RestfulService {

    /**
     * Whether to force an attempted update, regardless of cache status.
     */
    protected $forceUpdate = false;

    /**
     * Returns either the cached response if it is valid, or retrieves a new 
     * response from the server and returns that.
     *
     * If the server times out, or the response from the server is not an HTTP 
     * 200 OK response, and there is previously cached data, the previously 
     * cached data is returned.
     *
     * If all else fails, returns false.
     * @param String $subUrl The URL of the base server to query.
     */
    public function request($subURL = '', $method = "GET", $data = null, $headers = null, $curlOptions = array()) {
        $url = $this->getAbsoluteRequestURL($subURL);
		$cache_path = $this->getCacheFilename($url);

        if ( file_exists($cache_path) && (filemtime($cache_path) + $this->cache_expiry) >= time() && !$this->forceUpdate ) {
            // Unexpired cache file
            $store = file_get_contents($cache_path);
			$data = @unserialize($store);
			if ( $data ) {
			    return $data;
			}
        }

        $response = parent::request($subURL, $method, $data, $headers, $curlOptions);
        if ( $response->getStatusCode() == '200' ) {
            // Valid server response
            $store = serialize($response);
			file_put_contents($cache_path, $store);
			return $response;
        }

        if ( file_exists($cache_path) ) {
            // Server failed; use cache file
            $store = file_get_contents($cache_path);
			$data = @unserialize($store);
			if ( $data ) {
			    return $data;
			}
        }

        // No cache and server failed
        return false;
    }

    /**
     * Whether to force an update from the server, even if there is valid cached 
     * data (useful for debugging)
     */
    public function forceUpdate($update=true) {
        $this->forceUpdate = (bool)$update;
    }

    protected function getCacheFilename($url) {
        $cachedir = TEMP_FOLDER;	// Default silverstripe cache
		$cache_file = md5($url);	// Encoded name of cache file
		$cache_path = $cachedir."/xmlresponse_$cache_file";
		return $cache_path;
    }

}

